package homework05;

import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
import java.util.concurrent.Callable;//Callable 依赖 FutureTask 类获取返回结果。
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;

public class GetCountOfPrimeNumber {

	public static void main(String[] args) {
		System.out.println("请输入寻找素数的范围：0~");
		Scanner input = new Scanner(System.in);
		int maxRange = input.nextInt();
		System.out.println("请输入线程个数：");
		int numberOfThread = input.nextInt();
		long start = System.nanoTime();
		long numberOfPrimes = countPrimes(maxRange, numberOfThread);
		long end = System.nanoTime();
		System.out.printf("0~ %d 之间素数的个数是 %d\n", maxRange, numberOfPrimes);
		System.out.println("用" + numberOfThread + "个线程计算需要的时间是:" + (end - start) / 1.0e9 + "秒");

	}

	public static int countPrimes(int number, int numberOfThread) {
		int count = 0;// 统计各区间的素数个数
		try {
			List<Callable<Integer>> partitions = new ArrayList<Callable<Integer>>();
			int chunksPerPartion = number / numberOfThread;
			for (int i = 0; i < numberOfThread; i++) {
				int lower = (i * chunksPerPartion) + 1;
				int upper = (i == numberOfThread - 1) ? number : lower + chunksPerPartion - 1;
				// 定义一个内部类new Callable(),Callable能接受一个泛型，然后在call方法中返回一个这个类型的值
				CountPrimePerPart task = new CountPrimePerPart(lower, upper);
				partitions.add(task);
			}
			// 创建固定大小为numberOfThread的线程池
			ExecutorService executorPool = Executors.newFixedThreadPool(numberOfThread);
			/*
			 * invokeAll(tasks, timeout, unit) 批量提交限时任务
			 * 
			 * InvokeAll方法处理一个任务的容器（collection），并返回一个Future的容器。两个容器具有相同的结构：
			 * invokeAll将Future添加到返回的容器中，这样可以使用任务容器的迭代器，从而调用者可以将它表现的Callable与Future 关联起来。
			 * 当所有任务都完成时、调用线程被中断时或者超过时限时，限时版本的invokeAll都会返回结果。 超过时限后，任务尚未完成的任务都会被取消。
			 * 
			 * ———————————————— 版权声明：本文为CSDN博主「梦和远方」的原创文章，遵循 CC 4.0 BY-SA
			 * 版权协议，转载请附上原文出处链接及本声明。
			 * 原文链接：https://blog.csdn.net/weixin_42614447/article/details/88682854
			 */
			List<Future<Integer>> resultFromParts = executorPool.invokeAll(partitions, 10000, TimeUnit.SECONDS);
			executorPool.shutdown();// 执行完成之后关闭线程池
			for (final Future<Integer> result : resultFromParts)// 统计各任务的素数个数
				count += result.get();
		} catch (Exception ex) {
			throw new RuntimeException(ex);
		}
		return count;
	}
}
